﻿using System;
using UnityEditor.Search;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using XLFrame.NodeEditor.Extensions;
using ObjectField = UnityEditor.UIElements.ObjectField;

namespace XLFrame.NodeEditor
{
    public interface BaseInputVE
    {
        Type GetValueType();
        object ValueObject { get; set; }
    }
    
    /// <summary>
    /// 输入组件
    /// </summary>
    public abstract class BaseInputVE<T> : VEStyle ,BaseInputVE
    {
        /// <summary>
        /// 当值更新时
        /// </summary>
        public event Action<BaseInputVE<T>,T> OnValueChangedEvent;
        /// <summary>
        /// 当创建初始化加载数据时调用,下一帧运行
        /// </summary>
        public event Action<BaseInputVE<T>,T> OnInitValueEvent;
        public Label Label { get; private set; }
        public BaseField<T> BaseField {get; private set;}
        
        public T Value
        {
            get => BaseField.value;
            set => BaseField.value = value;
        }

        public Type GetValueType()
        {
            return typeof(T);
        }

        public object ValueObject
        {
            get => Value;
            set => Value = (T)value;
        }

        /// <summary>
        /// 输入标签容器
        /// </summary>
        public VisualElement FieldContainer { get; private set; } 
        
        /// <summary>
        /// Label最小宽度 默认60
        /// </summary>
        public float LabelMinWidth
        {
            get => Label.style.minWidth.value.value;
            set => Label.style.minWidth = value;
        }

        /// <summary>
        /// Label名称
        /// </summary>
        public string Name
        {
            get => Label.text;
            set
            {
                Label.text = value;
                Label.style.display = string.IsNullOrEmpty(value) ? 
                    DisplayStyle.None : DisplayStyle.Flex;
            }
        }
        
        protected BaseInputVE(string name = "",T defaultValue = default,AttributesData attributesData = null)
        {
            if (attributesData != null)
            {
                OnValueChangedEvent += (a,obj) => attributesData.SetAttribute(name, obj);
                Init(name,attributesData.GetAttribute<T>(name));
            }
            else
            {
                Init(name, defaultValue);
            }
        }

        void Init(string name, object defaultValue)
        {
            InitStyle(name, CreateInputField());
            if (defaultValue is not null)
            {
                BaseField.value = (T)defaultValue;
            }
            else
            {
                BaseField.value = default;
            }
            
            // 延迟到下一帧执行
            schedule.Execute(() =>
            {
                OnInitValueEvent?.Invoke(this, BaseField.value);
            }).StartingIn(1);
        }

        protected abstract BaseField<T> CreateInputField();

        private Label CreateLabel(string name)
        {
            if (Label is not null) return Label;
            Label = new Label(name);
            Label.style.minWidth = 60;
            Label.style.left = 3;
            Label.style.unityTextAlign = TextAnchor.MiddleLeft;
            if(String.IsNullOrEmpty(name))
                Label.style.display = DisplayStyle.None;
            return Label;
        }

        private void InitStyle(string name, BaseField<T> baseField)
        {
            FieldContainer = new VisualElement();
            FieldContainer.style.flexDirection = FlexDirection.Row;
            FieldContainer.style.flexGrow = 1;
            
            style.flexGrow = 0;
            style.flexDirection = FlexDirection.Column;
            
            Add(FieldContainer);
            
            this.BaseField = baseField;
            baseField.style.flexGrow = 1;
            
            baseField.RegisterValueChangedCallback(evt =>
            {
                OnValueChangedEvent?.Invoke(this,evt.newValue);
            });
            
            FieldContainer.Add(CreateLabel(name));
            FieldContainer.Add(baseField);
        }

    }
    
    public class InputTexture2DVE : BaseInputVE<UnityEngine.Object>
    {
        private VisualElement image;
        private bool isNoShowImage = false;
        public InputTexture2DVE(string name = "", Texture2D defaultValue = null,bool isNoShowImage=true,AttributesData attributesData = null) : base(name, defaultValue, attributesData)
        {
            this.isNoShowImage = isNoShowImage;
            image = new VisualElement();
            image.style.flexGrow = 1;
            
            Add(image);
            OnValueChanged(defaultValue);
        }

        protected override BaseField<UnityEngine.Object> CreateInputField()
        {
            ObjectField objectField = new ObjectField();
            objectField.objectType = typeof(Texture2D);
            objectField.RegisterValueChangedCallback(t=>OnValueChanged(t.newValue));
            return objectField;
        }
        
        private void OnValueChanged(UnityEngine.Object obj)
        {
            if(isNoShowImage)
                return;
            if (obj is null)
            {
                image.style.display = DisplayStyle.None;
            }
            else if (obj is Texture2D texture2D)
            {
                image.style.display = DisplayStyle.Flex;
                image.style.backgroundImage = new StyleBackground(texture2D);
                
                float wb = texture2D.height / (float)texture2D.width;
                image.style.SetMarginWidth(LabelMinWidth+3, 3, 0, 0);
                image.style.SetBorderWidth(1).SetBorderColor(new Color(0.2f,0.5f,0.6f,0.5f));
                schedule.Execute(() =>
                {
                    if (image.layout.width > 0)
                    {
                        image.style.height = wb * image.layout.width;
                    }
                    else
                    {
                        schedule.Execute(() => image.style.height = wb * image.layout.width).StartingIn(1);
                    }
                    
                }).StartingIn(1);
            }
        }
    }

    public class InputIntVE : BaseInputVE<int>
    {
        public InputIntVE(string name = "", int defaultValue = 0,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<int> CreateInputField() => new IntegerField();
    }
    public class InputLongVE : BaseInputVE<long>
    {
        public InputLongVE(string name = "", long defaultValue = 0,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<long> CreateInputField() => new LongField();
    }
    
    public class InputFloatVE : BaseInputVE<float>
    {
        public InputFloatVE(string name = "", float defaultValue = 0,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<float> CreateInputField() => new FloatField();
    }
    
    public class InputStringVE : BaseInputVE<string>
    {
        public InputStringVE(string name = "", string defaultValue = "",AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<string> CreateInputField() => new TextField();
    }
    
    public class InputBoolVE : BaseInputVE<bool>
    {
        public InputBoolVE(string name = "", bool defaultValue = false,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<bool> CreateInputField() => new Toggle();
    }
    
    public class InputVector2VE : BaseInputVE<Vector2>
    {
        public InputVector2VE(string name = "", Vector2 defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Vector2> CreateInputField() => new Vector2Field();
    }
    
    public class InputVector3VE : BaseInputVE<Vector3>
    {
        public InputVector3VE(string name = "", Vector3 defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Vector3> CreateInputField() => new Vector3Field();
    }
    public class InputVector2IntVE : BaseInputVE<Vector2Int>
    {
        public InputVector2IntVE(string name = "", Vector2Int defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Vector2Int> CreateInputField() => new Vector2IntField();
    }
    
    public class InputVector3IntVE : BaseInputVE<Vector3Int>
    {
        public InputVector3IntVE(string name = "", Vector3Int defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Vector3Int> CreateInputField() => new Vector3IntField();
    }
    
    public class InputVector4VE : BaseInputVE<Vector4>
    {
        public InputVector4VE(string name = "", Vector4 defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Vector4> CreateInputField() => new Vector4Field();
    }
    
    public class InputColorVE : BaseInputVE<Color>
    {
        public InputColorVE(string name = "", Color defaultValue = default,AttributesData attributesData = null) : base(name, defaultValue,attributesData){ }
        protected override BaseField<Color> CreateInputField() => new ColorField();
    }

}